home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-18 | 18.6 KB | 706 lines | [TEXT/MMCC] |
- /*
- File: AppLib.cp
-
- Contains: The “guts” of a Macintosh application.
-
- Written by: Dave Falkenburg and many other SmartFriends™
-
- Copyright: © 1993-94 by Dave Falkenburg, all rights reserved.
-
- Change History (most recent first):
-
- Oct 5, 94: Added GXDocWindow
- Global initialisation moved into main as Think Debugger doesnt like StdLib initialisation calling ToolBox!
- Discovered CodeWarrior cannot call ANY GX trap properly: returns result in A0 not D0 !
-
- */
- #ifdef SystemSevenOrLater
- #undef SystemSevenOrLater
- #endif
- #define SystemSevenOrLater 1
-
- #include <limits.h> // For LONG_MAX
-
- #include <Types.h>
- #include <Quickdraw.h>
- #include <Fonts.h>
- #include <Menus.h>
- #include <Windows.h>
- #include <Dialogs.h>
- #include <Desk.h>
- #include <Events.h>
- #include <AppleEvents.h>
- #include <DiskInit.h>
-
- #if qUseETO15Interfaces
- #include <Gestalt.h>
- #include <CodeFragments.h>
- #include <Devices.h>
- #else // qUseETO15Interfaces
- #include <GestaltEqu.h>
- #include <FragLoad.h>
- #endif // qUseETO15Interfaces
-
- #include <ToolUtils.h>
- #include <Traps.h>
- #include <LowMem.h>
-
- #include <Threads.h>
- #include <Drag.h>
- #include <Editions.h>
- //#include <OCEStandardMail.h>
-
- #if qInlineInputAware
- #include <TextServices.h>
- #include <TSMTE.h>
- #endif // qInlineInputAware
-
- #include "AppLib.h"
- #include "StandardMenus.h"
- #include "Window.h"
- #include "SplashWindow.h"
- #include "MailableWindow.h"
- #include "AppleEventHandling.h"
- #include "QDGXHeaders.h"
-
-
- // Function Prototypes
-
- void main(void);
- void MainEventLoop(void);
-
- void HandleMouseDown(TWindow * theWindowObj, EventRecord * pEvent);
- void HandleUpdate(EventRecord * pEvent);
- void HandleClose(WindowPtr pWindow);
- void WindowCommand(WindowPtr pWindow, short theMenuID, short theItem);
-
- // Globals
-
- Boolean gDone = false;
- Boolean gMenuBarNeedsUpdate = true;
-
- Boolean gHasColorQuickdraw = false;
- Boolean gHasThreadManager = false;
- Boolean gHasDragManager = false;
- Boolean gHasAppleScript = false;
- Boolean gHasAOCE = false;
- Boolean gHasDisplayManager = false;
-
- GrafPtr gWindowManagerPort;
- Rect gDeskRectangle;
- RgnHandle gMouseRegion = nil;
-
- short gPreferencesRsrcRefNum;
-
- #if qInlineInputAware
- Boolean gHasTextServices = false;
- Boolean gHasTSMTE = false;
- #endif
-
- #if qUseQuickDrawGX
- Boolean gHasQuickDrawGX = false;
- Boolean gGXDebugging = false;
- Boolean gGXValidation = false;
- long gQuickDrawGXVersion = 0;
- long gQuickDrawGXPrintingVersion = 0;
- gxGraphicsClient gQuickDrawGXClient = nil;
- #endif
-
- // Values that can be adjusted by other application code to change
- // the behavior of the MainEventLoop.
- //
- // Rules of thumb:
- //
- // Increase gXXXRunQuantum (and decrease gXXXSleepQuantum) when:
- // The application has many threads running that need time
- //
- // Decrease gXXXRunQuantum when:
- // Sending AppleEvents to other applications
- // Launching other applications
- // Running in the background
-
- // Think Debugger doesnt like StdLib initialisation calling ToolBox
- unsigned long gForegroundRunQuantum = 0;
- unsigned long gForegroundSleepQuantum = 4; // Δ in InitializeToolBox
- unsigned long gBackgroundRunQuantum = 0;
- unsigned long gBackgroundSleepQuantum = LONG_MAX;
-
- // Globals used to “tune” the performance of MainEventLoop
- // (assume we’ll be starting in the foreground)
-
- static unsigned long gRunQuantum;
- static unsigned long gSleepQuantum;
-
- #ifdef powerc
- #ifndef __MWERKS__
- QDGlobals qd;
- #endif
- #endif
-
- const short kMaxShort = 32767;
- #define Minimum(a, b) ((a) < (b) ? (a) : (b))
-
- void InitializeToolBox(short theNumOfCallsToMoreMasters);
- void InitializeToolBox(short theNumOfCallsToMoreMasters)
- {
- // Generic heap initialization.
- MaxApplZone();
- {
- THz pApplZone = ApplicationZone();
- short aSaveMoreMast = pApplZone->moreMast;
- long aNumMasterPointersDesired = aSaveMoreMast * theNumOfCallsToMoreMasters;
-
- // Here is a trick suggested by Jerome C.--it allocates one large block of master pointers
- for
- (
- aNumMasterPointersDesired = aSaveMoreMast * theNumOfCallsToMoreMasters;
- aNumMasterPointersDesired > 0;
- aNumMasterPointersDesired -= pApplZone->moreMast
- )
- {
- pApplZone->moreMast = (short)Minimum(aNumMasterPointersDesired, kMaxShort);
- MoreMasters();
- }
- pApplZone->moreMast = aSaveMoreMast;
- }
-
- // Think Debugger doesnt like StdLib initialisation calling ToolBox
- gForegroundSleepQuantum = GetCaretTime();
- gRunQuantum = gForegroundRunQuantum;
- gSleepQuantum = gForegroundSleepQuantum;
-
- // Start up the toolbox so we can notify people if there's a problem
- InitGraf(&qd.thePort);
- InitFonts();
- InitWindows();
- InitMenus();
- TEInit();
- InitDialogs(nil);
- }
-
- void main(void)
- {
- long feature;
-
- InitializeToolBox(6);
-
- if (GetToolTrapAddress(_Unimplemented) == GetOSTrapAddress(_Gestalt))
- FatalErrorAlert(kCoreErrorStrings, kUnsupportedSystemSoftware);
-
- if (Gestalt(gestaltQuickdrawFeatures,&feature) == noErr)
- gHasColorQuickdraw = ((feature & (1 << gestaltHasColor)) != 0);
-
- #if qUseQuickDrawGX
- // Check for and initialize QuickDrawGX
- if (Gestalt(gestaltGXVersion, &gQuickDrawGXVersion) == noErr)
- if (Gestalt(gestaltGXPrintingMgrVersion, &gQuickDrawGXPrintingVersion) == noErr)
- #ifdef powerc
- if ((Ptr) GXEnterGraphics != kUnresolvedSymbolAddress)
- gHasQuickDrawGX = true;
- #else
- gHasQuickDrawGX = true;
- #endif
-
- if (gHasQuickDrawGX)
- {
- // Initialize the graphics and printing environments. For additional details see "IM: QD GX Env & Utes."
- OSErr anErr = 1; // initialize for failure of GXNewGraphicsClient
- // The GXNewGraphicsClient routine defines the graphics heap size. If you do not make this
- // call, the GX graphics engine will create this heap automatically. How? It will create
- // a heap which is a percentage of your application's ideal memory foot print. This call
- // allows you to explicity define the ammount of memory used by the graphics system for
- // its graphics objects heap.
- // If you pass zero for the memoryLength (2nd) parameter, QuickDraw GX looks for a resource
- // of type 'gasz' with an ID of 0 and uses the first long word of that resource as the heap size.
- // If your application does not provide this resource, QuickDraw GX version 1.0 uses a default size of 600 KB.
- // gxClientAttribute: 0 = GX can expand heap, 1 (gxStaticHeapClient) = static heap
- // To determine the memory requirements of your graphics client heap: See IM: QD GX Env & Utes pp2-8,2-9
-
- gQuickDrawGXClient = GXNewGraphicsClient(nil, kGraphicsHeapSize, (gxClientAttribute) 0);
- if (gQuickDrawGXClient)
- {
- // NB: GXNewGraphicsClient() does not allocate memory to the heap yet.
- // This requires the GXEnterGraphics function call.
- GXEnterGraphics();
-
- anErr = GXGetGraphicsError(nil);
- // GXEnterGraphics() would fail only if there is not enough memory.
- // In this case, the graphics error posted is -27999 (out of memory).
- if (anErr != out_of_memory)
- {
- // Set gGXValidation to TRUE if you want run-time validation. As you increase the amount
- // of validation, The drawing speed will SLOW down due to all of the internal checking.
- if (gGXValidation)
- {
- gxValidationLevel aValidationLevel = gxPublicValidation; // check parameters to public routines
-
- // aValidationLevel |= gxInternalValidation;
- // aValidationLevel |= gxAllObjectValidation;
- // aValidationLevel |= gxApHeapValidation;
- // NB: Play with these enough and Validation becomes inconsistent
- GXSetValidation(aValidationLevel);
- }
-
- // If gGXDebugging = TRUE, you will receive graphics library errors & notices will be posted.
- // This functionality will only work with the "debugging" version of QuickDraw GX. If you
- // don't have the debugging version installed, these functions will not work.
- if (gGXDebugging)
- {
- SetGraphicsLibraryErrors();
- SetGraphicsLibraryNotices();
- }
- anErr = GXInitPrinting(); // See IM: QD GX Printing
- }
- }
- if (anErr)
- {
- if (gQuickDrawGXClient)
- GXDisposeGraphicsClient(gQuickDrawGXClient);
- gHasQuickDrawGX = false;
- }
- }
- if (gHasQuickDrawGX == false)
- FatalErrorAlert(kCoreErrorStrings, kNeedsQuickdrawGX);
-
- #endif
-
- TSplashWindow * splashWindow = new TSplashWindow;
-
- if ((Gestalt(gestaltAppleEventsAttr,&feature) == noErr) &&
- (feature & (1 << gestaltAppleEventsPresent)))
- {
- // Figure out if we need to do AppleEvent recording
- gHasAppleScript = (feature & (1 << gestaltScriptingSupport));
- }
- else
- FatalErrorAlert(kCoreErrorStrings,kUnsupportedSystemSoftware);
-
- #if qInlineInputAware
- if ((Gestalt(gestaltTSMgrVersion,&feature) == noErr) && (feature >= 1))
- {
- gHasTextServices = true;
- if (Gestalt(gestaltTSMTEAttr, &feature) == noErr)
- gHasTSMTE = (feature & (1 << gestaltTSMTEPresent));
- }
- #endif
-
- if (Gestalt(gestaltThreadMgrAttr,&feature) == noErr)
- {
- #ifdef powerc
- // If running on a PowerPC, make sure that we not only have the
- // 68K Thread Manager, but also the PowerPC shared library, too.
- // Because of the wonders of weak linking and out of memory errors
- // we need to also check to make sure that an entrypoint in the library
- // is there, too.
- if ((Ptr) NewThread != kUnresolvedSymbolAddress)
- gHasThreadManager = ((feature & ((1 << gestaltThreadMgrPresent) | (1 << gestaltThreadsLibraryPresent))) != 0);
- #else
- gHasThreadManager = ((feature & (1 << gestaltThreadMgrPresent)) != 0);
- #endif
- }
-
- // Check for and install Drag Manager callbacks
- if (Gestalt(gestaltDragMgrAttr,&feature) == noErr)
- {
- #ifdef powerc
- // If running on a PowerPC, make sure that we not only have the
- // 68K Drag Manager, but also the PowerPC shared library, too.
- if ((Ptr) NewDrag != kUnresolvedSymbolAddress)
- gHasDragManager = ((feature & ((1 << gestaltDragMgrPresent) | (1 << gestaltPPCDragLibPresent))) != 0);
- #else
- gHasDragManager = ((feature & (1 << gestaltDragMgrPresent)) != 0);
- #endif
-
- if (gHasDragManager)
- {
- InstallTrackingHandler(NewDragTrackingHandlerProc(CallWindowDragTrackingHandler),(WindowPtr) nil,nil);
- InstallReceiveHandler(NewDragReceiveHandlerProc(CallWindowDragReceiveHandler),(WindowPtr) nil,nil);
- }
- }
-
- // Check for Display Manager
- if (Gestalt(gestaltDisplayMgrAttr,&feature) == noErr)
- gHasDisplayManager = ((feature & (1 << gestaltDisplayMgrPresent)) != 0);
-
- // Check for and initialize AOCE Standard Mail package if it exists
- if ((Gestalt(gestaltSMPMailerVersion,&feature) == noErr) && (feature != 0))
- {
- #ifdef powerc
- if ((Ptr) SMPInitMailer != kUnresolvedSymbolAddress)
- gHasAOCE = (SMPInitMailer(kSMPVersion) == noErr);
- #else
- gHasAOCE = (SMPInitMailer(kSMPVersion) == noErr);
- #endif
- }
-
- // Install our AppleEvent Handlers
- InstallAppleEventHandlers();
-
- // Setup desktop rectangle for dragging windows around
- GetWMgrPort(&gWindowManagerPort);
- gDeskRectangle = (*GetGrayRgn())->rgnBBox;
-
- // Get the default menubar
- SetMenuBar(GetNewMBar(rMenuBar));
- AddResMenu(GetMHandle(mApple),'DRVR');
-
- #if qUseQuickDrawGX
- if (gQuickDrawGXClient)
- {
- // We initialize the CommonColors Library. This will allow us to set the color of a
- // shape by calling the SetShapeCommonColor function. We will need to call
- // DisposeCommonColors when we leave, to clean up the world.
- InitCommonColors();
- }
- #endif
-
- gPreferencesRsrcRefNum = OpenPreferencesResFile();
-
- if (SetupApplication() == noErr)
- {
- delete splashWindow; // get rid of the splash screen
- MainEventLoop();
- TearDownApplication();
- }
-
- #if qUseQuickDrawGX
- // Leaving. Close all the windows so we get rid of any data we or GX created. Then,
- // dispose of the common colors and exit the GX printing and graphics environment.
- if (gHasQuickDrawGX && gQuickDrawGXClient) // Tear down QuickDrawGX
- {
- DisposeCommonColors();
- GXExitPrinting(); // Close the new printing mgr.
- GXExitGraphics(); // Deallocate all of the default structures
- GXDisposeGraphicsClient(gQuickDrawGXClient);
- }
- #endif
- return;
- }
-
- void MainEventLoop(void)
- {
- EventRecord anEvent;
- unsigned long nextTimeToCheckForEvents = 0;
-
- while (! gDone)
- {
- if (gMenuBarNeedsUpdate)
- {
- gMenuBarNeedsUpdate = false;
- DrawMenuBar();
- }
-
- if ((gRunQuantum == 0) ||
- (TickCount() > nextTimeToCheckForEvents))
- {
- nextTimeToCheckForEvents = TickCount() + gRunQuantum;
-
- (void) WaitNextEvent(everyEvent,&anEvent,gSleepQuantum,gMouseRegion);
-
- HandleEvent(&anEvent);
- }
-
- if (gHasThreadManager)
- YieldToAnyThread();
- }
- }
-
- void HandleEvent(EventRecord *pEvent)
- {
- TWindow* pWindObj;
-
- pWindObj = GetWindowObject((pEvent->what == updateEvt) ? ((WindowPtr)pEvent->message) : FrontNonFloatingWindow());
-
- if (pWindObj)
- {
- pWindObj->AdjustCursor(pEvent);
- if (pWindObj->EventFilter(pEvent))
- return;
- }
-
- switch (pEvent->what)
- {
- case nullEvent:
- if (pWindObj)
- pWindObj->Idle(pEvent);
- else
- InitCursor();
- break;
-
- case mouseDown:
- HandleMouseDown(pWindObj, pEvent);
- break;
-
- case keyDown:
- case autoKey:
- if (pEvent->modifiers & cmdKey)
- {
- HandleSetupMenus(pWindObj);
- HandleMenu(pWindObj, MenuKey((short) pEvent->message & charCodeMask));
- }
- else
- if (pWindObj)
- pWindObj->KeyDown(pEvent);
- break;
-
- case updateEvt:
- HandleUpdate(pEvent);
- break;
-
- case diskEvt:
- if (pEvent->message >> 16)
- {
- static Point where = {50,50};
- (void)DIBadMount(where, pEvent->message);
- }
- break;
-
- case osEvt:
- switch ((pEvent->message & osEvtMessageMask) >> 24)
- {
- case mouseMovedMessage:
- break;
-
- case suspendResumeMessage:
- if (pEvent->message & resumeFlag)
- {
- gRunQuantum = gForegroundRunQuantum;
- gSleepQuantum = gForegroundSleepQuantum;
- }
- else
- {
- gRunQuantum = gBackgroundRunQuantum;
- gSleepQuantum = gBackgroundSleepQuantum;
- }
-
- SuspendResumeWindows((pEvent->message & resumeFlag) != 0);
- if (pEvent->message & convertClipboardFlag)
- ConvertClipboard();
- break;
- }
- break;
-
- case kHighLevelEvent:
- (void) AEProcessAppleEvent(pEvent);
- break;
-
- default:
- break;
- }
- }
-
- // Private structure of a MenuBar as returned by _GetMenuBar
- typedef struct // PrivateMenuData
- {
- MenuHandle menuHdl;
- short menuID;
- } PrivateMenuData, *PrivateMenuDataPtr;
-
- typedef struct // PrivateMBarData
- {
- Handle menuBarH;
- short menuBarID;
- } PrivateMBarData;
-
- typedef struct // PrivateMenuBar
- {
- PrivateMBarData mBar;
- PrivateMenuData menuArr[1]; // NB: list terminated with null menuHdl
- } PrivateMenuBar, *PrivateMenuBarPtr, **PrivateMenuBarHdl;
-
- void EnableAllMenus(Boolean theEnableFlag)
- {
- Handle hMbar = GetMenuBar(); // no fail on GetMenuBar()
- short aMenuCount = (GetHandleSize(hMbar)-sizeof(PrivateMBarData))/sizeof(PrivateMenuData);
- PrivateMenuDataPtr pMenuData = (*(PrivateMenuBarHdl)hMbar)->menuArr;
-
- HLock(hMbar);
- while (aMenuCount-- > 0)
- {
- short aItemCount;
- if (pMenuData->menuHdl) // list terminates with null menuHdl
- for (aItemCount = CountMItems(pMenuData->menuHdl); aItemCount > 0; --aItemCount)
- // DONT touch item 0: this means ALL items
- if (theEnableFlag)
- EnableItem(pMenuData->menuHdl, aItemCount);
- else
- DisableItem(pMenuData->menuHdl, aItemCount);
- ++pMenuData;
- }
- DisposeHandle(hMbar);
- DrawMenuBar();
- }
-
- void EnableOneMenu(short theMenuID, Boolean theEnableFlag)
- {
- MenuHandle hMenu = GetMHandle(theMenuID);
- short aItemCount;
- if (hMenu)
- for (aItemCount = CountMItems(hMenu); aItemCount > 0; --aItemCount)
- // DONT touch item 0: this means ALL items
- if (theEnableFlag)
- EnableItem(hMenu, aItemCount);
- else
- DisableItem(hMenu, aItemCount);
- }
-
- void EnableMenuItem(short theMenuID, short theItem, Boolean theEnableFlag)
- {
- MenuHandle hMenu = GetMHandle(theMenuID);
- if (hMenu && theItem) // DONT touch item 0: this means ALL items
- if (theEnableFlag)
- EnableItem(hMenu, theItem);
- else
- DisableItem(hMenu, theItem);
- }
-
- void UpdateWindowMenu(void)
- {
- MenuHandle hMenu = GetMHandle(mWindows);
- if (hMenu)
- {
- Str63 aName;
- WindowPtr pWindow;
- TWindow* topWindowObj = nil;
- short aItemCount;
-
- for (aItemCount = CountMItems(hMenu); (aItemCount > iDivider1mWindows); --aItemCount)
- DelMenuItem(hMenu, aItemCount);
- // Walk the window list for Windows menu
- for (pWindow = FrontNonFloatingWindow(); pWindow; pWindow = (WindowPtr)((WindowPeek)pWindow)->nextWindow)
- {
- TWindow *pWindObj = GetWindowObject(pWindow);
- if (pWindObj)
- {
- GetWTitle(pWindow, aName);
- aItemCount = 1+CountMItems(hMenu); // append new item
- InsMenuItem(hMenu, "\p•", aItemCount); // aName wont be parsed
- SetItem(hMenu, aItemCount, aName);
- if (topWindowObj == nil)
- { // this is frontmost TWindow
- topWindowObj = pWindObj;
- CheckItem(hMenu, aItemCount, true);
- }
- }
- }
- }
- EnableOneMenu(mWindows, true);
- }
-
- void HandleSetupMenus(TWindow * topWindowObj)
- {
- EnableAllMenus(false);
- EnableOneMenu(mApple, true);
-
- EnableMenuItem(mFile, iNew, true);
- EnableMenuItem(mFile, iOpen, true);
- EnableMenuItem(mFile, iPreferences, true);
- EnableMenuItem(mFile, iQuit, true);
- EnableMenuItem(mEdit, iShowOrHideClipboard, true);
- if (gHasAOCE)
- EnableMenuItem(mDebug, iNewMailableWindow, true);
- UpdateWindowMenu();
- if (topWindowObj)
- topWindowObj->SetupMenus();
- DrawMenuBar();
- }
-
- void HandleMouseDown(TWindow * theWindowObj,EventRecord *pEvent)
- {
- WindowPtr pWindow;
- short partCode;
- TWindow *pWindObj;
-
- partCode = FindWindow(pEvent->where, &pWindow);
- pWindObj = GetWindowObject(pWindow);
-
- switch(partCode)
- {
- case inMenuBar:
- HandleSetupMenus(theWindowObj);
- HandleMenu(theWindowObj, MenuSelect(pEvent->where));
- break;
-
- case inSysWindow:
- SystemClick(pEvent,pWindow);
- break;
-
- case inContent:
- if (pWindObj)
- {
- SetPort(pWindow);
- pWindObj->Click(pEvent);
- }
- break;
-
- case inDrag:
- if (pWindObj)
- pWindObj->Drag(pEvent->where);
- break;
-
- case inGrow:
- if (pWindObj)
- pWindObj->Grow(pEvent->where);
- break;
-
- case inGoAway:
- if (TrackGoAway(pWindow,pEvent->where))
- HandleClose(pWindow);
- break;
-
- case inZoomIn:
- case inZoomOut:
- if (TrackBox(pWindow,pEvent->where,partCode))
- if (pWindObj)
- pWindObj->Zoom(partCode);
- break;
-
- default:
- break;
- }
- }
-
- void HandleUpdate(EventRecord * pEvent)
- {
- WindowPtr pWindow = (WindowPtr) pEvent->message;
- TWindow* pWindObj = GetWindowObject(pWindow);
-
- if (pWindObj)
- {
- CSavePort aSavePort(pWindow);
- BeginUpdate(pWindow);
- pWindObj->Draw();
- EndUpdate(pWindow);
- }
- }
-
- void WindowCommand(WindowPtr pWindow, short theMenuID, short theItem)
- {
- if (pWindow)
- {
- TWindow *pWindObj = GetWindowObject(pWindow);
- if (pWindObj)
- pWindObj->HandleMenuCommand(theMenuID, theItem);
- }
- }
-
- void HandleClose(WindowPtr pWindow)
- {
- if (pWindow)
- {
- short windowKind = ((WindowPeek) pWindow)->windowKind;
- if (windowKind < 0)
- CloseDeskAcc(windowKind);
- else
- {
- TWindow *pWindObj = GetWindowObject(pWindow);
- if
- (
- pWindObj && pWindObj->CanClose()
- && pWindObj->Close() && pWindObj->DeleteAfterClose()
- )
- delete pWindObj;
- }
- }
- }
-